/* game of tic-tac-toe with:
 * custom size of stage
 * custom number of players
 * mixed AI and players
 */
class WorldTicTacToe extends World {

	/* assets for this world */
	assets() {
		return [
			"images/stage_empty.png",
			"images/stage_p1.png",
			"images/stage_p2.png",
			"images/stage_p3.png",
			"images/stage_p4.png",
			"images/stage_p5.png",
			"images/stage_p6.png",
			"images/button_quit.png",
			"images/button_restart.png",
		];
	}
	
	/* runs before assets are initialized,
	 * used to get data from previous world
	 */
	constructor(data) {
		super(data);

		/* save who is AI and who is player */
		this.ai = data.ai;
		this.max_players = data.max_players;
		this.returner = data;
		this.stage_x = data.stage_x;
		this.stage_y = data.stage_y;
		this.mode = data.mode;

	} /* constructor */

	/* initialization */
	start() {

		/* text style */
		this.text_style = new PIXI.TextStyle({
			fill: "#ff0000",
			fontSize: 40,
		});

		/* game data */
		this.current_player = this.max_players;
		this.playing = true;

		/* stage */
		this.stage = [];

		for (let i = 0; i < this.stage_x *this.stage_y; i++) {
			this.stage.push(0);
		}

		/* stage appearence */
		this.stage_sprite = [];
		for (let i = 0; i < this.stage.length; i++) {
			this.stage_sprite[i] = new PIXI.Sprite(
				loader.resources["images/stage_empty.png"].texture
			);
			this.stage_sprite[i].x = width /(this.stage_x+1) *(i%this.stage_x+1);
			this.stage_sprite[i].y = height /(this.stage_y+1) *(Math.floor(i/this.stage_x)+1);
			this.stage_sprite[i].anchor = {x:0.5, y:0.5};
			this.stage_sprite[i].hitArea = new PIXI.Rectangle(0, 0, 100, 100);
			app.stage.addChild(this.stage_sprite[i]);
		}

		/* current player text */
		this.text_cplayer = new PIXI.Text("Hello World", 
			this.text_style);
		this.text_cplayer.anchor = {x:0.5, y:1.0};
		this.text_cplayer.x = width/2;
		this.text_cplayer.y = height;
		app.stage.addChild(this.text_cplayer);

		/* restart button (visible when game ends) */
		this.button_restart = new PIXI.Sprite(
			loader.resources["images/button_restart.png"].texture
		);
		this.button_restart.visible = false;
		app.stage.addChild(this.button_restart);

		/* quit button */
		this.button_quit = new PIXI.Sprite(
			loader.resources["images/button_quit.png"].texture
		);
		this.button_quit.anchor = {x:1, y:0};
		this.button_quit.x = width;
		app.stage.addChild(this.button_quit);

		/* AI timer */
		this.ai_timer = 0;
		this.ai_max = 40;

		/* time attack mode depends on value of timer:
		 * -1: disabled
		 * positive: enabled
		 */
		this.timer = -1;
		this.max_timer = 90;
		if (this.mode === "time") {
			this.timer = this.max_timer;

			this.text_timer = new PIXI.Text(
				"timer", this.text_style);
			this.text_timer.anchor = {x:0.5, y:0};
			this.text_timer.x = width/2;
			app.stage.addChild(this.text_timer);
		}

		/* start game */
		this.end_turn();
	}

	/* player touched stage,
	 * if touched on empty part,
	 * 	fill it and move to next player
	 */
	update() {

		/* timer on time attack */
		if (this.playing && this.timer > 0) {

			this.timer--;
			this.text_timer.text = "time: " +this.timer;

			if (this.timer == 0) {
				this.end_turn();
			}

		}

		/* AI */
		if (this.playing && this.ai[this.current_player-1]) {

			/* advance timer */
			this.ai_timer++;

			/* time to make a move */
			if (this.ai_timer >= this.ai_max) {

				/* find all empty cells */
				let empty_stage = [];
				for (let i = 0; i < this.stage.length; i++) {
					if (this.stage[i] == 0) {
						empty_stage.push(i);
					}
				}

				/* pick one of the cells */
				let target = empty_stage[Math.floor( Math.random() *empty_stage.length )];

				/* make move
				 * if for any reason it picks
				 * an occupied cell, it will restart
				 */
				this.make_move(target);

				/* restart timer for next bot */
				this.ai_timer = 0;

			} /* make move */

			/* ignore all input and updates while AI is playing */
			return;

		} /* AI */

		/* handle input */
		for (let e = 0; e < input.length; e++) {

			/* mouse left click */
			if (input[e].which == 1) {

				/* clicking point */
				let p = new PIXI.Point(input[e].offsetX, input[e].offsetY);

				/* clicked on quit button */
				if (this.button_quit.containsPoint(p)) {

					/* quit to menu */
					return world_list.indexOf(WorldMenu);

				} /* quit menu */
			
				/* game is finished
				 * touch only restart and quit button
				 */
				if (!this.playing) {
				
					/* restart button */
					if (this.button_restart.containsPoint(p)) {
	
						/* restart this world */
						return world_list.indexOf(WorldTicTacToe);
	
					} /* restart button */

					/* stop any other input */
					break;

				}

				/* through all buttons */
				for (let i = 0; i < this.stage_sprite.length; i++) {

					/* touched button */
					if (this.stage_sprite[i].containsPoint(p)) {

						this.make_move(i);

						/* touch only one button at a time */
						break;

					} /* touched button */

				} /* find button */

			} /* left click */

		} /* handle input */

	} /* update */

	/* check if someone won the game */
	check_victory() {

		/* divine the map into smaller 3x3 boxes, and
		 * check them individually
		 */
		for (let x = 0; x <= this.stage_x-3; x++)
		for (let y = 0; y <= this.stage_y-3; y++) {

			/* save result as it's the winner or draw
			 * if it's 0, ignore it
			 */
			let res = this.check_box(x, y);
			if (res != 0) {
				return res;
			}
		}
		
		/* no-one won yet */
		return 0;

	} /* check victory */

	/* checks a 3x3 box on the map, starting from x,y
	 * to find a winner
	 */
	check_box(x, y) {

		let stage = this.stage;
		let sp = x+(y*this.stage_x);
		let rows = this.stage_x;

		/* check rows-lines */
		for (let i = 0; i < 3; i++) {

			let hor = sp+(i*rows);

			/* horizontal */
			if (stage[hor] == stage[hor+1]
			&& stage[hor+1] == stage[hor+2]
			&& stage[hor] != 0) {
				return stage[hor];
			}

			let ver = sp+i;

			/* vertical */
			if (stage[ver] == stage[ver+rows]
			&& stage[ver+rows] == stage[ver+rows*2]
			&& stage[ver] != 0) {
				return stage[ver];
			}
		}

		/* diagonal */
		if (stage[sp] == stage[sp+rows+1]
		&& stage[sp+rows+1] == stage[sp+rows*2+2]
		&& stage[sp] != 0) {
			return stage[sp];
		}

		/* other diagonal */
		if (stage[sp+2] == stage[sp+rows+1]
		&& stage[sp+rows+1] == stage[sp+rows*2]
		&& stage[sp+2] != 0) {
			return stage[sp+2];
		}

		/* if all cells are filled, and there is no winner
		 * it is a draw
		 */
		let draw = true;
		for (let i = 0; i < this.stage_x *this.stage_y; i++) {
			if (this.stage[i] == 0) {
				draw = false;
				break;
			}
		}

		if (draw) {
			return -1;
		}

		/* no-one won yet */
		return 0;

	} /* check box */

	/* ends current player's turn */
	end_turn() {

		/* move to the next player */
		if (++this.current_player > this.max_players) {
			this.current_player = 1;
		}

		/* depending on the value of victory:
		 * -1: draw
		 *  0: game still running
		 *  >0: player with that number won
		 */
		let v = this.check_victory();
		if (v > 0) {
			this.playing = false;
			this.text_cplayer.text =
				"player " +v +" won!";
			this.button_restart.visible = true;
			return;
		}
		else
		if (v == -1) {
			this.playing = false;
			this.text_cplayer.text = "Draw!";
			this.button_restart.visible = true;
			return;
		}

		/* update current player text */
		let txt_player = this.ai[this.current_player-1] ? "computer" : "player";
		this.text_cplayer.text = txt_player +": " +this.current_player;

		/* in time attack, reset timer for new player */
		if (this.timer >= 0) {
			this.timer = this.max_timer;
		}

	} /* end turn */
	
	/* if i is empty cell,
	 * mark it with current player and return true
	 * else return false
	 */
	make_move(i) {

		/* if square is empty, 
		 * fill it with current player's index,
		 * end turn
		 */
		if (this.stage[i] == 0) {
			this.stage[i] = this.current_player;
			this.stage_sprite[i].texture =
				loader.resources["images/stage_p" 
					+this.current_player +".png"].texture;
			this.end_turn();
			return true;
		}

		/* not cell changed */
		return false;

	} /* make move */

} /* world tic-tac-toe */
